/* 算法实现模板 */
import AlgorithmBase from "./AlgorithmBase";
import { mdRender} from "../../../common/Common";

import { showMathStringInTable } from "../../../visual/Table2D";
import { drawDecisionTree } from "../../../visual/Tree2D";
import { DeNode } from "../../../common/DecisionTreeFuncs";

import 'katex/dist/katex.min.css';

class InformationGain extends AlgorithmBase{
  constructor(){
    super('InformationGain');
    // this.model          = {dataSet:[ ],label:[ ],alpha:10.0}
    this.descriptionUrl = `${this.homepage}/data/slm/ch5/5.1/README.md`;
    this.datasetUrl     = `${this.homepage}/data/slm/ch5/5.1/dataset.json`;

    this.trainLog = [];
    this.len = 0
    this.Ct = 0 
    this.max = 0
    this.flag = 0
    this.node_name_ = ''
    this.cmd =''
    this.width = 0
  }

  init(){ 
    this.reset();

    this.initTrainDS();
  }
  
  reset(){
    this.dataset = undefined;
    this.trainDS = undefined;
    

    this.clear();

    this.initDescription();
    this.updateModel();
  }

  loadModel(json){
    if(json.TrainDS){
      if(json.TrainDS instanceof Array){
        this.trainDSList = [];
        for(let i = 0, il = json.TrainDS.length; i < il; i++){
          const dat = json.TrainDS[i];
          this.trainDSList.push(dat);
        }
        this.trainDS = this.trainDSList[0];
      }
      else{
        let trainDS = json.TrainDS;
        this.trainDS = trainDS;
      }
    }
    return this.trainDS
  }
  
  // 模型UI
  // initModelUI(){
  //   this.addLabel(this.domElementList.model, '参数a：');
  //   this.alphaInput = this.addFloatInput(
  //     this.domElementList.model, this.model.alpha, 
  //     (event)=>{
  //       const val = parseFloat(event.target.value);
  //       this.model.alpha = val;
  //       this.updateModel();
  //     });

  //   this.modelDiv = this.addDiv(this.domElementList.model);
  // }

  // 渲染模型到页面
  updateModel(data, label, tree){

    // 显示数据集
    if(this.trainDS){
      if(data === undefined) data = this.trainDS.dataSet;
      console.log(data);
      if(label === undefined) label = this.trainDS.label;

      // const modelString = String.raw
      // `$$ \begin{aligned} \alpha&:=${this.model.alpha}\end{aligned} $$`

      // mdRender(`${modelString}`, this.inputDiv);

      var table_data = [];

      var data_label_ = ["ID"];
      for(var i=0;i<label.length;i++){
        data_label_.push("\\textbf{"+label[i]+"}")
      }

      table_data.push(data_label_);

      for(var j=0;j<data.length;j++){
        var data_=[]
        data_.push((j+1).toString())
        for(var k=0;k<data[j].length;k++){
          data_.push("\\textbf{"+data[j][k]+"}")
        }
        table_data.push(data_)
      }
      if(this.inputDiv) this.inputDiv.innerHTML = '';
      showMathStringInTable(this.inputDiv,table_data);
      
    }
  }

  // 输入数据UI
  initInputUI(){

    // 文件选择器
    const fileSelector      = document.createElement('input');
    fileSelector.type       = 'file';
    fileSelector.hidden     = true;
    fileSelector.onchange   = this.handleFileChange.bind(this);   
    
    this.addButton(this.domElementList.input, "获取服务器数据", this.initTrainDS.bind(this));
    this.addButton(this.domElementList.input, "使用本地数据", this.openFileSelector.bind(this));
    this.domElementList.input.appendChild(fileSelector);
    this.addButton(this.domElementList.input, "训练", this.train.bind(this));
    // this.playButton = this.addButton(this.domElementList.input, "训练动画", this.trainAnimation.bind(this));
    // this.playButton.hidden = true;

    this.labelTrainTips = this.addLabel(this.domElementList.input, '');
    this.inputDiv       = this.addDiv(this.domElementList.input);

    this.fileSelector  = fileSelector;
  }

  // 输出UI
  initOutputUI(){
    this.outputDiv   = this.addDiv(this.domElementList.output);
    this.trainLogDiv = this.addDiv(this.domElementList.output);
  }

  // 获取描述md文件
  initDescription(){
    fetch(this.descriptionUrl).then((response)=>{
      return response.text();
    }).then((txt)=>{

      this.reandMD(txt, this.descriptionDiv)
    })
  }

  // 获取服务器数据集
  initTrainDS(){
    this.prepare(this.datasetUrl);
  }

  // 准备数据训练数据
  prepare(url){
    fetch(url).then((response)=>{
      return response.json();
    }).then((json)=>{
      this.trainDS = this.loadModel(json);
      this.updateModel();
    })
  }

  openFileSelector(){
    this.fileSelector.click();
  }
  // 获取文件路径加载
  handleFileChange(event){
    const files = event.target.files;

    for(let i = 0, il = files.length; i < il; i++){
      let reader = new FileReader();
      reader.onload = (e) => {      
        this.prepare(e.target.result);
        if(i === files.length - 1){
          event.target.value = '';
        }
      };
      reader.readAsDataURL(files[i])
    }
  }

  entropy(y){
    let N = y.length;
    let count = {'借款':0,'不借':0};
    for(let i = 0,il=y.length;i<il;i++){
      if(y[i]===0){
        count.借款 = count.借款+1
      }
      if(y[i]===1){
        count.不借=count.不借+1;
      }
    }
    let entropy = 0;
    entropy = -(count.借款/N)*(Math.log2(count.借款/N))-(count.不借/N)*(Math.log2(count.不借/N));
    return entropy;

  }
  cond_entropy(x, y, cond){
    let N = y.length;
    let cond_x = [];
    
    for(let i = 0,il=x.length;i<il;i++){
      cond_x.push(x[i][cond])
    }
    let tmp_entro = [];
    let set_cond_x = [];
    for(let i=0,il=cond_x.length;i<il;i++){
      if(set_cond_x.indexOf(cond_x[i])===-1){
        set_cond_x.push(cond_x[i])
      }
    }
    for(let i=0,il=set_cond_x.length;i<il;i++){
      let tmp_y =[];
      for(let j=0,jl=cond_x.length;j<jl;j++){
        if (cond_x[j]===set_cond_x[i]){
          tmp_y.push(y[j]);
        } 
      }
      tmp_entro.push(tmp_y.length/N*this.entropy(tmp_y));
    }
    let tmp_entro_ = [];

    for(let i=0,il=tmp_entro.length;i<il;i++){
     if(tmp_entro[i]!==NaN){
       tmp_entro_.push(tmp_entro[i]);
     }
     if(tmp_entro[i]!==tmp_entro[i]){
       tmp_entro_[i]=0
     }

   }
    let sum = 0;
    for(let i =0,il=tmp_entro_.length;i<il;i++){
      sum = parseFloat(sum)+parseFloat(tmp_entro_[i]);
    }
    return sum;

  }
  imformationgain(x,y,cond){
    return this.entropy(y)-this.cond_entropy(x,y,cond);
  }

  // 训练
  train(){
    var dataSet = this.trainDS.dataSet;
    var label = this.trainDS.label;
    let d = {'青年':1, '中年':2, '老年':3, '一般':1, '好':2, '极好':3, '有':0, '没有':1,'同意':0,'拒绝':1};
    let data = [];
    for(let i =0 ,il=dataSet.length;i<il;i++){
      let tmp =[];
      let t =dataSet[i]
      for (let j =0 ,jl=dataSet[0].length;j<jl;j++){
        tmp.push(d[dataSet[i][j]]);
      }
      data.push(tmp);
    }
    let y = [];
    var x = [];
    let x_len = dataSet[0].length-1

    for(let i=0,il=dataSet.length;i<il;i++){
      let tmp = [];
      y.push(data[i][data[0].length-1]);
      for(let j=0,jl=x_len;j<jl;j++){
        tmp.push(data[i][j]);
      }
      x.push(tmp);
    }
    let imformationgain_table = [];
    imformationgain_table.push([String.raw`\textbf{特征}`,String.raw`\textbf{信息增益}`]);
    var il = label.length-1;
    for(let i=0;i<il;i++){
      imformationgain_table.push([]);
      imformationgain_table[i+1][0]=label[i];
      imformationgain_table[i+1][1]=String(this.imformationgain(x,y,i));
    }   
    if(this.trainLogDiv) this.trainLogDiv.innerHTML = '';
    showMathStringInTable(this.trainLogDiv, imformationgain_table);
    

  }
}


export default InformationGain;